﻿using ReprojectWebMercator.GLSL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace ReprojectWebMercator
{

    public class GLSLFuncBase
    {
        #region abs
        public static float abs(float a)
        {
            return Math.Abs(a);
        }
        public static vec2 abs(vec2 a)
        {
            return new vec2(Math.Abs(a.x), Math.Abs(a.y));
        }
        public static vec3 abs(vec3 a)
        {
            return new vec3(Math.Abs(a.x), Math.Abs(a.y), Math.Abs(a.z));
        }
        public static vec4 abs(vec4 a)
        {
            return new vec4(Math.Abs(a.x), Math.Abs(a.y), Math.Abs(a.z), Math.Abs(a.w));
        }
        #endregion

        #region lessThanEqual
        public ComparerEnum4 lessThanEqual(vec4 a, vec4 b)
        {
            return new ComparerEnum4(a.x - b.x<=0, a.y - b.y <= 0, a.z - b.z <= 0, a.w - b.w <= 0);
        }
        public ComparerEnum3 lessThanEqual(vec3 a, vec3 b)
        {
            return new ComparerEnum3(a.x - b.x <= 0, a.y - b.y <= 0, a.z - b.z <= 0);
        }
        public ComparerEnum2 lessThanEqual(vec2 a, vec2 b)
        {
            return new ComparerEnum2(a.x - b.x <= 0, a.y - b.y <= 0);
        }
        #endregion

        #region all
        public bool all(ComparerEnum3 a)
        {
            return a.v1 && a.v2 && a.v3;
        }
        public bool all(ComparerEnum2 a)
        {
            return a.v1 && a.v2;
        }
        public bool all(ComparerEnum4 a)
        {
            return a.v1 && a.v2 && a.v3 && a.v4;
        }
        #endregion

        #region texture
        public static vec4 texture2D(sampler2D sampler2D,vec2 uv)
        {
            var tx = (int)(uv.x * sampler2D.Width)% sampler2D.Width;
            var ty = (int)(uv.y * sampler2D.Height) % sampler2D.Height;
            while (tx < 0) { tx += sampler2D.Width; }
            while (ty < 0) { ty += sampler2D.Height; }
            var color = sampler2D.GetPixel(tx, ty);
            return new vec4(color.R/255.0, color.G / 255.0, color.B / 255.0, color.A / 255.0);
        }
        #endregion

        #region 片元着色器
        public virtual vec4 PixelPassMain(vec2 v) { return vec4(1.0f); }
        public Color[,] GetPixelPass()
        {
            Color[,] bitmap = new Color[512,512];
            for (var ii = 0; ii < 512; ii++)
            {
                for (var jj = 0; jj < 512; jj++)
                {
                    var i = ii / 512.0f;
                    var j = jj / 512.0f;

                    var p = PixelPassMain(vec2(i, j));
                    var r = (int)(p.x * 255);
                    if (r > 255) r = 255;
                    if (r < 0) r = 0;

                    var g = (int)(p.y * 255);
                    if (g > 255) g = 255;
                    if (g < 0) g = 0;

                    var b = (int)(p.z * 255);
                    if (b > 255) b = 255;
                    if (b < 0) b = 0;

                    var a = (int)(p.w * 255);
                    if (a > 255) a = 255;
                    if (a < 0) a = 0;

                    Color color = Color.FromArgb(a,r, g, b);
                    bitmap[(int)(i * 512), (int)(j * 512)]= color;
                }
            }
            return bitmap;
        }

        public Image ColorToImage(Color[,] res)
        {
            var len2 = res.GetLength(1);
            Bitmap bitmap=new Bitmap(res.GetLength(0), len2);
            for(var i=0; i<res.GetLength(0); i++)
            {
                for(var j=0; j<res.GetLength(1); j++)
                {
                    bitmap.SetPixel(i, len2-1-j, res[i,j]);
                }
            }
            return bitmap;
        }
        #endregion

        #region dot
        public static float dot(vec3 a, vec3 b)
        {
            return a.x * b.x + a.y * b.y + a.z * b.z;
        }
        public static float dot(vec4 a, vec4 b)
        {
            return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
        }
        public static float dot(vec2 a, vec2 b)
        {
            return a.x * b.x + a.y * b.y;
        }
        #endregion

        #region sign
        public static float sign(float t)
        {
            if (t < 0) return -1.0f;
            if(t>0) return 1.0f;
            return 0;
        }
        #endregion

        #region mix
        public static vec4 mix(vec4 a, vec4 b, float c)
        {
            return new vec4(
                a.x * (1 - c) + b.x * c,
                a.y * (1 - c) + b.y * c,
                a.z * (1 - c) + b.z * c,
                a.w * (1 - c) + b.w * c);
        }
        public static vec3 mix(vec3 a, vec3 b, float c)
        {
            return new vec3(
                a.x * (1 - c) + b.x * c,
                a.y * (1 - c) + b.y * c,
                a.z * (1 - c) + b.z * c);
        }
        #endregion

        #region pow
        public static vec4 pow(vec4 a, vec4 b)
        {
            return new vec4(Math.Pow(a.x, b.x), Math.Pow(a.y, b.y), Math.Pow(a.z, b.z), Math.Pow(a.w, b.w));
        }
        #endregion

        #region min
        public static float min(float a, float b)
        {
            return Math.Min(a, b);
        }
        public static float min(double a, double b)
        {
            return (float)Math.Min(a, b);
        }
        public static vec2 min(vec2 a, vec2 b)
        {
            return new vec2(Math.Min(a.x, b.x), Math.Min(a.y, b.y));
        }
        public static vec3 min(vec3 a, vec3 b)
        {
            return new vec3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z));
        }
        public static vec4 min(vec4 a, vec4 b)
        {
            return new vec4(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z), Math.Min(a.w, b.w));
        }
        public static float max(float a, float b)
        {
            return Math.Max(a, b);
        }
        public static float max(double a, double b)
        {
            return (float)Math.Max(a, b);
        }
        public static vec2 max(vec2 a, vec2 b)
        {
            return new vec2(Math.Max(a.x, b.x), Math.Max(a.y, b.y));
        }
        public static vec3 max(vec3 a, vec3 b)
        {
            return new vec3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z));
        }
        public static vec3 max(vec3 a, double b)
        {
            return new vec3(Math.Max(a.x, b), Math.Max(a.y, b), Math.Max(a.z, b));
        }
        public static vec4 max(vec4 a, double b)
        {
            return new vec4(Math.Max(a.x, b), Math.Max(a.y, b), Math.Max(a.z, b), Math.Max(a.w, b));
        }
        public static vec4 max(vec4 a, vec4 b)
        {
            return new vec4(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z), Math.Max(a.w, b.w));
        }
        #endregion

        #region step
        public static float step(float edge, float x)
        {
            if (x < edge) return 0.0f;
            return 1.0f;
        }
        public static float step(double edge, double x)
        {
            if (x < edge) return 0.0f;
            return 1.0f;
        }
        public static vec3 step(vec3 a, vec3 b)
        {
            return new vec3(step(a.x, b.x), step(a.y, b.y), step(a.z, b.z));
        }
        public static vec4 step(double edge, vec4 b)
        {
            return new vec4(step(edge, b.x), step(edge, b.y), step(edge, b.z), step(edge, b.w));
        }
        public static vec4 step(vec4 edge, vec4 x)
        {
            return new vec4(step(edge.x, x.x), step(edge.y, x.y), step(edge.z, x.z), step(edge.w, x.w));
        }
        #endregion

        #region normalize
        public static vec3 normalize(vec3 a)
        {
            var len = length(a);
            return new vec3(a.x / len, a.y / len, a.z / len);
        }
        public static vec2 normalize(vec2 a)
        {
            var len = length(a);
            return new vec2(a.x / len, a.y / len);
        }
        #endregion

        public static float atan(double a, double b)
        {
            return (float)Math.Atan2(a, b);
        }

        #region sin
        public static float sin(double a)
        {
            return (float)Math.Sin(a);
        }
        public static float cos(float v)
        {
            return (float)Math.Cos(v);
        }
        #endregion

        #region mod
        public static float mod(float a,float b)
        {
            return a % b;
        }
        public static float mod(double a, double b)
        {
            return (float)(a % b);
        }
        #endregion

        #region smoothStep
        public static float smoothstep(float t1, float t2, float x)
        {
            // Scale, bias and saturate x to 0..1 range
            // 还记得么？在remap算法中接触过
            x = clamp((float)((x - t1) / (t2 - t1)), 0.0f, 1.0f);
            // Evaluate polynomial
            return x * x * (3 - 2 * x);
        }
        public static float smoothstep(double t1, double t2, double x)
        {
            // Scale, bias and saturate x to 0..1 range
            // 还记得么？在remap算法中接触过
            x = clamp((float)((x - t1) / (t2 - t1)), 0.0f, 1.0f);
            // Evaluate polynomial
            return (float)(x * x * (3 - 2 * x));
        }
        public static vec2 smoothstep(vec2 t1, vec2 t2, vec2 t3)
        {
            float x = smoothstep(t1.x, t2.x, t3.x);
            float y = smoothstep(t1.y, t2.y, t3.y);
            return new vec2(x, y);
        }
        #endregion

        #region clamp
        protected static float clamp(float a, float b, float c) { return Math.Clamp(a, b, c); } 
        #endregion

        public static float length(vec2 v)
        {
            return (float)Math.Sqrt(v.x * v.x + v.y * v.y);
        }
        public static float length(vec3 v)
        {
            return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
        }
        #region floor
        public static float floor(float a) { return (float)Math.Floor(a); }
        public static float floor(double a) { return (float)Math.Floor(a); }
        public static vec3 floor(vec3 a) { return new vec3((float)Math.Floor(a.x), (float)Math.Floor(a.y), (float)Math.Floor(a.z)); }
        public static vec4 floor(vec4 a) { return new vec4((float)Math.Floor(a.x), (float)Math.Floor(a.y), (float)Math.Floor(a.z), (float)Math.Floor(a.w)); }
        public static vec2 floor(vec2 a) { return new vec2((float)Math.Floor(a.x), (float)Math.Floor(a.y)); }
        #endregion

        #region vec4
        public static vec4 vec4(double a)
        {
            return new vec4(a, a, a, a);
        }
        public static vec4 vec4(vec2 a, vec2 b)
        {
            return new vec4(a.x, a.y, b.x, b.y);
        }
        public static vec4 vec4(float a, float b, float c, float d) { return new vec4(a, b, c, d); }
        public static vec4 vec4(double a, double b, double c, double d) { return new vec4(a, b, c, d); }
        public static vec4 vec4(vec2 v, float c, float d) { return new vec4(v.x, v.y, c, d); }
        public static vec4 vec4(vec3 v, float d) { return new vec4(v.x, v.y, v.z, d); }
        public static vec4 vec4(float d) { return new vec4(d, d, d, d); } 
        #endregion

        #region vec3
        public static vec3 vec3(float a) { return new vec3(a, a, a); }
        public static vec3 vec3(vec2 a,double b) { return new vec3(a.x, a.y, b); }
        public static vec3 vec3(double a) { return new vec3((float)a, (float)a, (float)a); }
        public static vec3 vec3(double a, double b, double c)
        {
            return new vec3((float)a, (float)b, (float)c);
        }
        #endregion

        #region vec2
        public static vec2 vec2(float a, float b) { return new vec2(a, b); }
        public static vec2 vec2(double a, double b) { return new vec2(a, b); }
        public static vec2 vec2(float a) { return new vec2(a, a); }
        public static vec2 vec2(double a) { return new vec2(a, a); }
        #endregion

        #region vec2
        public static mat2 mat2(float m11, float m12,float m21,float m22) { return new mat2(m11, m12,m21,m22); }
        public static mat2 mat2(double m11, double m12, double m21, double m22) { 
            return new mat2((float)m11, (float)m12, (float)m21, (float)m22); }
        #endregion

        #region fract
        protected vec3 fract(vec3 v)
        {
            return new vec3(v.x - floor(v.x), v.y - floor(v.y), v.z - floor(v.z));
        } 
        #endregion
    }
}
